import json
import random
import re
import time

from elasticsearch import Elasticsearch
import requests
from django.contrib.auth.hashers import check_password
from django.contrib.auth.hashers import make_password
from django.db import transaction
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from rest_framework.response import Response
from rest_framework.settings import api_settings
from rest_framework.views import APIView
from tools.myjwt import *
from hospital.models import *
from hospital.serializer import *
from tools.myredis import r
from tools.comm import send_message, get_alipay

# Create your views here.

class RegisterView(APIView):
    def post(self, request):
        serializer = UserSerializer(data=request.data)

        if serializer.is_valid():
            # 对密码进行哈希处理
            hashed_password = make_password(serializer.validated_data['password'])

            # 由于我们不直接使用serializer.save()，需要手动创建对象并设置字段
            user = UserModel.objects.create(
                name=serializer.validated_data['name'],
                mobile=serializer.validated_data['mobile'],
                password=hashed_password,  # 使用哈希后的密码
                email=serializer.validated_data['email'],
                pic_url=serializer.validated_data.get('pic_url', ''),  # 处理默认值
            )

            return Response({"status": "success", "message": "User registered successfully."})
        else:
            return Response(serializer.errors)




class LoginView(APIView):

    def post(self, request):
        mobile = request.data.get('mobile')
        passwd = request.data.get('password')

        if not all([mobile, passwd]):
            return Response({'code': 1001, 'msg': '数据不可为空'})

        ret = re.match(r'^1[3-9]\d{9}$', mobile)
        if not ret:
            return Response({'code': 1002, 'msg': '手机号不符合规则'})

        user = UserModel.objects.filter(mobile=mobile).first()
        if not user:
            return Response({'code': 1003, 'msg': '手机号未注册'})

        # 因为模型没有check_password方法，手动比对密码哈希值
        # 注意：这里假设password字段已经是哈希值
        if not check_password(passwd, user.password):
            return Response({'code': 1004, 'msg': '密码错误'})
        token = myjwt.jwt_encode({'data': {'id': user.id}})
        print(token)
        mobile = user.mobile[0:3]+'****'+user.mobile[-5:-1]
        data = {'token': token, 'id': user.id, 'account': '测试用户', 'mobile': mobile, 'avatar': '', 'refreshToken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjIwMSIsImlhdCI6MTcxNTE2ODc3OSwiZXhwIjoxNzE2NDY0Nzc5fQ.nt58noCuX6MUbLwGRFNiwOGWApk7AJmH-lcELNSTda0' }
        return Response({'code': 10000, 'msg': '登录成功', 'data': data})

class SmsView(APIView):
    def get(self, request):
        mobile = request.GET.get('mobile')
        type = request.GET.get('type')
        if not all([mobile,type]):
            return Response({'code': 1001, 'msg':'手机号不可为空'})
        value = r.str_get(type)
        if value:
            return Response({'code': 1002, 'msg': '重复发送'})
        randamcode = random.randint(100000, 999999)
        print(randamcode)
        send_message(randamcode, mobile, 1)
        r.str_set_exp(type, 180, randamcode)
        return Response({'code': 200})
class SmsLoginView(APIView):
    def post(self,request):
        data = request.data
        mobile = data['mobile']
        code = data['code']
        value = r.str_get('login')
        if value:
            if int(value) == int(code):
                user = UserModel.objects.filter(mobile=mobile).first()
                if not user:
                    useradd = UserModel(mobile=mobile)
                    useradd.save()
                token = myjwt.jwt_encode({'data':{'userid': user.id}})
                data = {'token': token, 'id': user.id, 'account': '测试用户', 'mobile': mobile, 'avatar': '', 'refreshToken': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjIwMSIsImlhdCI6MTcxNTE2ODc3OSwiZXhwIjoxNzE2NDY0Nzc5fQ.nt58noCuX6MUbLwGRFNiwOGWApk7AJmH-lcELNSTda0'}
                return Response({'code': 10000, 'msg': '登陆成功', 'data': data})
            else:
                return Response({'code':10012,'msg':'验证码不正确'})
        return Response({'code':10010, 'msg':'手机验证码已过期'})

# class WbtalkLoginView(APIView):
#     def

class DingDingtalkView(APIView):
    def get(self, request):
        from urllib.parse import quote
        params = [
            f"redirect_uri={quote('http://127.0.0.1:8000/user/dingtalkCallback/')}",
            "response_type=code",
            "client_id=dinghobgdxnjuewjxivc",
            "scope=openid",
            "prompt=consent"
        ]
        url = "https://login.dingtalk.com/oauth2/auth?" + ("&".join(params))
        return Response({"url": url})


class WbCallback(APIView):
    def get(self,request):
        code = request.GET.get("code")
        cid = "2128742316"
        uri = 'http://127.0.0.1:8000/wbcallback/'
        cit = 'b96a2d41469cfddeafc34dd0ecb66aad'

        url = "https://api.weibo.com/oauth2/access_token?client_id=%s&client_secret=%s&grant_type=authorization_code&redirect_uri=%s&code=%s" % (cid, cit, uri, code)
        res = requests.post(url)
        resdata = json.loads(res.text)
        print(resdata)
    #     1.获取code，accress_token接口发起Post请求，uid和token-》
        uid = resdata['uid']
        token = resdata['access_token']
    # 2.通过uid去sf_login表中查询，如果存在，联表查询用户信息，用用户信息生成token跳转到vue
        sflogin = ThirdpartyModel.objects.filter(uid=uid).first()
        if sflogin:
            user = sflogin.userid
            user.exptime = int(time.time())
            token = myjwt.jwt_encode({'id': user.id})
            return redirect("http://localhost:8080/#/updateToken?userid="+str(user.id)+"&token="+token)
        else:
            return redirect("http://localhost:3001/bindMobile?uid="+str(uid)+"&token="+token)

    def post(self,request):
        #获取参数
        data = json.loads(request.body)
        mobile = data['mobile']
        uid = data['uid']
        # 5.提交，根据手机号查询用户表，如果存在写入三方登录表
        user = UserModel.objects.filter(mobile=mobile).first()
        # 6.如果不存在，写入用户表，写入三方登录表
        if not user:
            user = UserModel(mobile=mobile)
            user.save()
        #进行查询再写入
        sflogin =ThirdpartyModel(userid=user, uid=uid, login_type=4)
        sflogin.save()
        # 7.用用户信息生成token返回,在vue页面中存入localStorage中，跳转到首页
        user.username = mobile
        token = myjwt.jwt_encode({'userid': user.id})
        return Response({"code": 10000, 'data': {'userid': user.id, 'token': token}})

# class PatientView(APIView):
#     def post(self, request):
#         data = request.data
#
#         count = PatientModel.objects.filter(userid=data['userid']).count()
#
#         if count < 6:
#             if data['is_default'] == 'True' or data['is_default'] == '1':
#                 patient = PatientModel.objects.filter(userid=data['userid'],is_default=True).update(is_default=False)
#             ser = PatientSer(data=data)
#             if ser.is_valid():
#
#                 ser.save()
#
#                 return Response({'code': 10000, 'msg': '患者添加成功'})
#
#             else:
#
#                 return Response({'code': 10011, 'msg': '添加失败', 'err': ser.errors})
#
#         else:
#             return Response({'code': 10010, 'msg': '同一账号最多只能添加六名患者'})
#
#     def get(self, request):
#         userid = request.GET.get('userid')
#
#         patient = PatientModel.objects.filter(userid=userid).all()
#
#         ser = PatientSer(patient, many=True)
#
#         return Response({'code': 10000, 'data': ser.data})

class DepartmentView(APIView):
    def get(self,request):
        types = request.GET.get('types')
        dep = Department.objects.filter(pid__isnull=True).all()
        ser = DepartmentSer(dep, many=True)
        return Response({"code": 10000, 'data': ser.data})

import os
from qiniu import Auth
class QnToken(APIView):
    def get(self,request):

        # 需要填写你的 Access Key 和 Secret Key
        access_key = 'ujSifBf6pPWw_N8wbr-BlMZmI2erJqT8N3Lriy8n'
        secret_key = 'Ruo8FnFbxxgwm-346Jee9tH0HUkFeLJJOBPKus-A'
        # 构建鉴权对象
        q = Auth(access_key, secret_key)
        # 要上传的空间
        bucket_name = 'stupy00'
        # 上传后保存的文件名
        # key = 'haha'
        # 生成上传 Token，可以指定过期时间等
        # 上传策略示例
        # https://developer.qiniu.com/kodo/manual/1206/put-policy
        # policy = {
        #     # 'callbackUrl':'https://requestb.in/1c7q2d31',
        #     # 'callbackBody':'filename=$(fname)&filesize=$(fsize)'
        #     # 'persistentOps':'imageView2/1/w/200/h/200'
        # }
        # 3600为token过期时间，秒为单位。3600等于一小时
        token = q.upload_token(bucket_name)
        print(token)
        if token:
            return Response({'code': 10000, 'token': token})

class PatientView(APIView):
    def get(self, request):
        id = request.GET.get('id')
        userid = request.GET.get('userid', 1)
        if id:
            patient = PatientModel.objects.filter(id=id).first()
            ser = PatientSer(patient)
            return Response({'code': 10000, 'data': ser.data})
        patients = PatientModel.objects.filter(userid_id=userid).all()
        ser = PatientSer(patients, many=True)
        return Response({"code": 10000, 'data': ser.data})

class PreorderView(APIView):
    def get(self, request):
        type = request.GET.get('type')
        illnessType = request.GET.get('illnessType')
        header = request.headers.get('Authorization')
        a = str(header).strip('Bearer')
        b = a.strip()
        token = myjwt.jwt_decode(b)
        print(token)
        userid = token['data']['id']
        # user = UserModel.objects.filter(id=userid)
        # score = user.tscore
        pointDedution = 0
        fee = FeeModel.objects.filter(types=type, docker_types=illnessType).first()

        payment = fee.money

        couponDeduction = 0
        couponId = 0
        dict={'pointDedution': pointDedution, 'couponDeduction': couponDeduction, 'couponId': couponId, 'payment': payment, 'actualPayment':payment}
        return Response({'code': 10000, 'data': dict})


import random, time
from tools.myredis import r
import uuid
class OrdersKey(APIView):
    def get(self,request):
        #生成唯一标识
        key = uuid.uuid1().hex
        #将key存入redis
        r.str_set(key,key)
        #返回
        return Response({"code": 10000, 'data': {"key": key}})

class OrdersView(APIView):
    def post(self, request):
        # 获取数据
        data = request.data
        print(data)
        # 接口幂等性判断
        key = data['orderkey']
        mes = r.str_get(key)
        if not mes:
            return Response({"code":400,'message':'不能重复生成订单'})
        r.key_del(key)
        # 从token中获取
        userid = 2
        # {'type': 2, 'illnessType': 1, 'depId': 4,  'couponId': 0}
        score = 0
        couponmoney = 0
        tmoney = 0
        pay_money = 0
        # 根据优惠卷couponId查询优惠金额
        if data['couponId'] > 0:
            coupon = CouponsModel.objects.filter(id=data['couponId']).first()
            couponmoney = coupon.money

        # 查询订单金额
        # 支付费用
        fee = FeeModel.objects.filter(types=data['type'], docker_types=data['illnessType']).first()
        tmoney = fee.money

        # 查询可用的积分
        users = UserModel.objects.filter(id=userid).first()
        userscore = users.tscore
        # 判断订单的支付金额，
        p_money = tmoney - couponmoney
        # 付的钱多于积分
        if p_money > userscore:
            score = userscore
        elif p_money < userscore:
            score = p_money
        # 支付金额
        pay_money = tmoney - couponmoney - score
        # 生成订单号
        orderno = str(int(time.time())) + str(userid) + str(random.randint(10000, 99999))
        orderdict = {'orderno': orderno, "descrip": data['illnessDesc'], 'times': data['illnessTime'],
                     'pic_url': json.dumps(data['pictures']), 'is_into': data['consultFlag'],
                     'patient': data['patientId'], 'userid': userid, 'status': 1,
                     'transaction': '0', 'pay_type': 1, 'doctor_types': data['illnessType'],
                     'types': data['type'], 'department': data['depId'], 'score': score,
                     'couponid': data['couponId'], 'couponmoney': couponmoney, 'tmoney': tmoney, 'money': pay_money}
        # 写入订单表
        print(data['illnessType'])
        ser = OrdersSer(data=orderdict)
        if ser.is_valid():
            ser.save()
            return Response({"code": 10000, 'data': {"id": orderno}})
        print(ser.errors)
        # 记录积分使用情况，优惠卷
        return Response({"code": 400, 'err': ser.errors})

class Payview(APIView):
    def post(self, request):
        payUrl = ''
        pay_money = 0
        # 获取参数 订单号和支付方式
        orderno = request.data['orderId']
        paymentMethod = request.data['paymentMethod']
        # 根据订单号查询订单实付金额
        orders = MedicalConsultationOrder.objects.filter(orderno=orderno).first()
        if orders:
            pay_money = orders.money
        else:
            return Response({'code': '10010', 'msg': '订单不存在，不能支付'})

        # 调用支付宝封装支付链接
        if paymentMethod == 1:
            pay = get_alipay()
            query_params = pay.direct_pay(
                subject='问诊支付',
                out_trade_no=str(orderno),
                total_amount=float(pay_money)
            )
            payUrl = 'https://openapi-sandbox.dl.alipaydev.com/gateway.do?{0}'.format(query_params)
            print(payUrl)
            return Response({"code": 10000, 'data': {"payUrl": payUrl}})
        else:
            paymentMethod = 2
            # 更新订单表中支付方式
            orders.pay_type = paymentMethod
            orders.save()
            # 返回链接
            return Response({"code": 10000, 'data': {"payUrl": payUrl}})
    @transaction.atomic()
    def get(self,request):
        mes = request.GET
        data = {k: v for k, v in mes.items()}
        pay = get_alipay()
        # 验证签名
        pay = get_alipay()
        sign = data.pop('sign')
        flag = pay.verify(data, sign)
        # 判断是否通过，如果通过
        if flag:
            # 获取订单号
            # 支付宝流水号
            transaction_no = data['trade_no']
            # 订单号
            order_no = data['out_trade_no']
            sid = transaction.savepoint()
            try:
                # 2.更新订单表为已支付状态
                orders = MedicalConsultationOrder.objects.filter(orderno=order_no).first()
                if orders:
                    orders.status = 2
                    orders.transaction = transaction_no
                    orders.save()
                # 3.判断是否使用积分，更新积分记录表，用户表中总积分减少
                if orders.score > 0:
                    ScoreModel.objects.create(userid=orders.userid, l_type=2, score=orders.score)
                    tusers = UserModel.objects.filter(id=orders.userid).first()
                    tusers.tscore -= int(orders.score)
                    tusers.save()
                # 4.是否使用优惠卷，更新用户优惠卷表中的使用状态
                if orders.couponid > 0:
                    UserCoupons.objects.filter(id=orders.couponid).update(status=2)
                transaction.savepoint_commit(sid)
                return HttpResponseRedirect('http://localhost/room/')
            except:
                transaction.savepoint_rollback(sid)

        return HttpResponseRedirect('http://localhost/pay_error')

class InterrogationView(APIView):
    def get(self, request):
        type = request.GET.get('type')
        current = request.GET.get('current')
        pageSize = request.GET.get('pageSize')
        header = request.headers.get('Authorization')
        a = str(header).strip('Bearer')
        b = a.strip()
        token = myjwt.jwt_decode(b)
        print(token)
        userid = token['data']['id']
        total = MedicalConsultationOrder.objects.filter(userid=userid).count()
        start = (int(current)-1)*int(pageSize)
        end = start + int(pageSize)
        order = MedicalConsultationOrder.objects.filter(userid=userid).all()[start:end]
        list = []
        for i in order:
            dict1 = {'id': i.id, 'type': i.doctor_types, 'illnessType': i.types, 'depId': i.department.id, 'illnessDesc': i.descrip, 'illnessTime': i.times, 'consultFlag': i.is_into, 'pictures': i.pic_url, 'pateientId': i.patient.id, 'couponId': i.couponid}
            list.append(dict1)

        return Response({'code': 10000, 'data': list, 'pageTotal': total})

# import pymysql
# class Address(APIView):
#     def get(self, request):
#         db_config = {
#             'host': 'localhost',  # 或数据库的实际主机地址
#             'port': 3306,  # MySQL默认端口
#             'user': 'root',
#             'password': 'shao2580',
#             'database': 'fg_data',
#             'charset': 'utf8mb4',  # 推荐使用utf8mb4支持更多字符集
#         }
#
#         try:
#             # 创建连接
#             connection = pymysql.connect(**db_config)
#
#             # 创建游标
#             cursor = connection.cursor()
#
#             # 执行SQL查询
#             cursor.execute("SELECT * FROM tb_areas")
#
#             # 获取所有结果
#             results = cursor.fetchall()
#
#             for row in results:
#                 print(row)
#
#             # 关闭合游标和连接
#             cursor.close()
#             connection.commit()  # 如果有写操作，提交事务
#             connection.close()
#
#         except pymysql.Error as e:
#             print(f"发生错误: {e}")
#         finally:
#             # 确保即使有异常也关闭连接
#             if connection:
#                 connection.close()

class EsFind(APIView):
    def get(self, request):
        es = Elasticsearch('http://124.70.12.172:9200/')
        title = request.GET.get('title')
        start = 0
        page_size = 3
        dsl = {
            'query': {
                'match': {'title': title}
            },
            'from': start,
            'size': page_size,
            '_source': ['title', 'content']
        }
        print(dsl)
        res = es.search(index='dockor', body=dsl)
        print(res['hits']['hits'])
        return Response({'code': 200})




API_KEY = "2akmUzdlIVuPGXbRYABdvmUi"
SECRET_KEY = "IfOmHcqlOB9RSbDfVwSVvy23EYX87o46"


def get_access_token():
    """
    使用 AK，SK 生成鉴权签名（Access Token）
    :return: access_token，或是None(如果错误)
    """
    url = "https://aip.baidubce.com/oauth/2.0/token"
    params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
    return str(requests.post(url, params=params).json().get("access_token"))
class Baiduview(APIView):
    def get(self,request):
        uri=request.GET.get('pic_url')
        url = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic?access_token=" + get_access_token()

        payload = f'url={uri}&detect_direction=false&detect_language=false&paragraph=false&probability=false'
        headers = {
            'Content-Type': 'application/x-www-form-urlencoded',
            'Accept': 'application/json'
        }
        response = requests.request("POST", url, headers=headers, data=payload)

        print(response.text)
        return Response({'code': 200 ,'data': response.text})

from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.pydantic_v1 import BaseModel,Field

from langchain_community.llms.tongyi import Tongyi
from langchain.chains import LLMChain   

class commentType(BaseModel):
    comment: str = Field(description="病情描述部分")
    commentType :str = Field(description="判断病情需要到哪个科室的结果")
    

class JudgeDepartmentview(APIView):
    
    def post(self, request):
        
        illnessDesc = request.data.get('illnessDesc')
        
        departmentlist = Department.objects.filter(pid__isnull=False)
        department = '、'.join(map(lambda x: x.name, departmentlist))
        
        prommpt = '医院有下面几个科室：'+department+'，请根据病情描述判断应该去哪个科室。\n{format_instructions}\n病情描述：{illnessDesc}'
        
        print(prommpt)
        
        parser = JsonOutputParser(pydantic_object=commentType)
                
        prommptTemplate = PromptTemplate(
            template=prommpt,
            input_variables=["illnessDesc"],
            partial_variables={"format_instructions": parser.get_format_instructions()}      
        )
        
        llm = Tongyi()
        
        # chain = LLMChain(llm=llm, prompt=prommptTemplate,output_parser=parser)
        
        chain  = prommptTemplate | llm | parser
        
        ret = chain.invoke({"illnessDesc": illnessDesc})
        
        print(ret)
        
        return Response({'code': 200, 'data': ret.get('commentType') , 'msg': 'ok'})

from hospro import settings
from django.http import StreamingHttpResponse

class KnowledgeChatview(APIView):
    
    def post(self,request):
        
        data = json.loads(request.body)
        
        header = {"Content-Type":"application/json"}        
        
        url = settings.KNOWLEDGE_URL
        
        if (data.get('stream')):            
            return StreamingHttpResponse(self.stream_response(requests.post(url,headers=header,json=data,stream=True)),status=200,content_type='text/event-stream')
            
        else:        
            ret = requests.post(url,headers=header,json=data).json()
            
            return  Response({'code': 200, 'data': ret.get('data') , 'msg': 'ok'})
        
    def stream_response(self,responses):
        for data in responses.iter_content(chunk_size=None):
            if data:
                yield data
        
        
        

